package cn.maihe.elg.operation.centers.follow.handler;

import cn.maihe.elg.operation.centers.follow.enums.FollowRespCode;
import cn.maihe.elg.operation.centers.follow.exception.FollowException;
import cn.maihe.elg.operation.centers.supports.BaseCenterService;
import cn.maihe.elg.operation.centers.supports.annotation.CenterTradeService;
import cn.maihe.elg.operation.exception.CenterException;
import cn.maihe.elg.operation.model.enums.CenterNoEnum;
import cn.maihe.elg.operation.model.enums.CenterProviderEnum;
import cn.maihe.elg.operation.model.enums.InnerRespCode;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.collect.Lists;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.context.request.async.DeferredResult;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.net.SocketTimeoutException;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CompletableFuture;

/**
 * @Description 随行对接
 * @Author WJH
 * @Date 2021/08/02
 */
@RestController
@RequestMapping(value = "/v1/center/" + FollowHandler.centerNo)
@Slf4j
public class FollowHandler {


    protected final ObjectMapper objectMapper = new ObjectMapper();
    /**
     * FIXME 固定后管初始化值
     * 中心编号：取值CenterNoEnum.FOLLOW.getCenterNo
     */
    public static final String centerNo = "C0598";

    private final Map<String, BaseCenterService> tradeServiceMap = new HashMap<>();

    @Value("${spring.profiles.active}")
    private String activeProfile;

    public static final CenterNoEnum curCenterNo = CenterNoEnum.SANMING;
    public static final CenterProviderEnum centerProvider = CenterProviderEnum.FOLLOW;
    public static final List<String> enableCenterNos = Lists.newArrayList(
            CenterNoEnum.SANMING.getCenterNo());

    public FollowHandler(@SuppressWarnings("rawtypes") final Collection<BaseCenterService> baseCenterServices) {
        super();
        baseCenterServices.forEach(item -> {
            CenterTradeService ts = AnnotationUtils.findAnnotation(item.getClass(), CenterTradeService.class);
            if (centerProvider == ts.provider()) {
                tradeServiceMap.put(ts.tradeType().name().toLowerCase(), item);
            }
        });
    }


    @PostMapping(value = "/{orgCode}/{tradeType}", consumes = {"application/json"})
    public @ResponseBody
    DeferredResult<Object> service(@PathVariable("orgCode") String orgCode, @PathVariable("tradeType") String tradeType, @RequestBody final String map, final HttpServletRequest req, final HttpServletResponse resp) {
        return this.doService(orgCode, tradeType, req, resp, map, null);
    }

    @SuppressWarnings("unchecked")
    protected DeferredResult<Object> doService(final String orgCode, final String tradeType, final HttpServletRequest req, final HttpServletResponse resp, final String parameters, final Map<String, MultipartFile> multipartFileMap) {

        JSONObject body = null;
        DeferredResult<Object> dr = new DeferredResult<Object>();

        if (!this.tradeServiceMap.containsKey(tradeType.toLowerCase())) {
            try {
//                dr.setResult(OutEncrptAndSign.outEncryptAndSign(HdlRespModelUtil.error(null, HbZbankException.of(HbZbankRespCode.REQUEST_ILLEGAL, "不支持的交易类型", null)), tradeType, hbZbankAuthConfig.getFromZbankPubKey()));
            } catch (Exception e) {
                log.error("加签错误", e);
            }
            FollowBaseResp respModel;
            respModel = new FollowBaseResp(FollowRespCode.FAILURE.getRespCode(), "不支持接口交易", null);
            dr.setResult(respModel);
            return dr;
        }
        log.error("请求参数：{}", parameters);
//        log.error("请求参数：{}", JSON.toJSONString(parameters));
//        Map<String, Object> param = new HashMap<>();
//        body.forEach((k, v) -> {
//            param.put(k, v);
//        });

        CompletableFuture
                .supplyAsync(() -> {
                    try {
//                        String data =
                        String data = parameters.split("\"data\":")[1];
                        if (data.contains("}}")) {
                            data = data.split("}}")[0];
                            if (data.contains("}]")) {
                                data = data.concat("}");
                            } else if (data.contains("},")) {
                                data = data.concat("}}");
                            } else {
                                data = data.concat("}");
                            }
                        } else {
                            data = data.split("},")[0].concat("}");
                        }
                        SignReqDTO signReqDTO = JSONObject.parseObject(parameters, SignReqDTO.class);
                        signReqDTO.setData(data);
                        return this.tradeServiceMap.get(tradeType.toLowerCase()).doService(orgCode, signReqDTO, parameters, multipartFileMap);
                    } catch (Exception e) {
                        throw e;
                    }
                })
                .whenCompleteAsync((baseResp, t) -> {
                    FollowBaseResp respModel;
                    if (t != null) {
                        if (t instanceof FollowException) {
                            respModel = new FollowBaseResp(FollowRespCode.FAILURE.getRespCode(), t.getMessage(), baseResp);
                        } else if (null != t.getCause() && t.getCause() instanceof FollowException) {
                            respModel = new FollowBaseResp(FollowRespCode.FAILURE.getRespCode(), t.getCause().getMessage(), baseResp);
                        } else if (t instanceof CenterException) {
                            respModel = new FollowBaseResp(FollowRespCode.FAILURE.getRespCode(), t.getMessage(), baseResp);
                        } else if (t.getCause() != null && t.getCause() instanceof CenterException) {
                            respModel = new FollowBaseResp(FollowRespCode.FAILURE.getRespCode(), t.getCause().getMessage(), baseResp);
                        } else if (t instanceof SocketTimeoutException) {
                            respModel = new FollowBaseResp(FollowRespCode.FAILURE.getRespCode(), "请求超时", baseResp);
                        } else {
                            respModel = new FollowBaseResp(FollowRespCode.FAILURE.getRespCode(), "处理异常", baseResp);
                        }
                        log.error("中心：{},交易类型：{},服务错误：{}", curCenterNo.getCenterName(), tradeType, t.getMessage(), t);
                        dr.setResult(respModel);
                    } else {
                        respModel = new FollowBaseResp(FollowRespCode.SUCCESS.getRespCode(), "处理成功", baseResp);
                        dr.setResult(respModel);
                    }
                    log.info("中心：{},交易类型：{},响应报文：{}", curCenterNo.getCenterName(), tradeType, JSON.toJSONString(respModel));
                });

        return dr;
    }

    private FollowException toFollowException(CenterException ce) {
        InnerRespCode innerRespCode = ce.getInnerRespCode();
        FollowRespCode followRespCode = FollowRespCode.FAILURE;
        //待优化明细
        if (innerRespCode.isFailure()) {
            followRespCode = FollowRespCode.FAILURE;
        } else if (innerRespCode.isException()) {
            followRespCode = FollowRespCode.FAILURE;
        } else if (innerRespCode.isTimeOut()) {
            followRespCode = FollowRespCode.FAILURE;
        }
        return FollowException.of(followRespCode, ce.getMessage(), ce.getCause());
    }

}



